<template>
  <main class="scan-container">
    <div class="scan-card">
      <div class="scan-header">
        <h1 class="scan-title">
          <i class="fas fa-qrcode"></i>
          扫码录入
        </h1>
        <div class="scan-status" :class="scanStatus">
          <i :class="getStatusIcon()"></i>
          {{ getStatusText() }}
        </div>
      </div>

      <!-- PLC配置区域 -->
      <div class="plc-config-section">
        <div class="config-header">
          <h3 class="config-title">
            <i class="fas fa-cog"></i>
            PLC配置
            <span v-if="configSaved" class="config-saved-indicator">
              <i class="fas fa-check"></i>
              已保存
            </span>
            <span v-if="!isConfigComplete" class="config-incomplete-indicator">
              <i class="fas fa-exclamation-triangle"></i>
              未完成
            </span>
          </h3>
          <button @click="toggleConfigPanel" class="toggle-config-btn">
            <i :class="showConfigPanel ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"></i>
            {{ showConfigPanel ? '收起' : '展开' }}
          </button>
        </div>
        
                 <!-- 配置状态提示 -->
         <div v-if="!isConfigComplete && showConfigPanel" class="config-status-alert">
           <i class="fas fa-info-circle"></i>
           <span>请完成以下配置：{{ missingConfigText }}</span>
         </div>
        
        <div class="config-panel" v-show="showConfigPanel">
          <div class="config-grid">
            <div class="config-item">
              <label class="config-label">
                <i class="fas fa-globe"></i>
                IP地址
              </label>
              <input
                id="plc-ip"
                v-model="plcConfig.ipAddress"
                class="config-input"
                type="text"
                placeholder="127.0.0.1"
                @focus="handleConfigFocus"
                @blur="handleConfigBlur"
              />
            </div>
            <div class="config-item">
              <label class="config-label">
                <i class="fas fa-ethernet"></i>
                端口
              </label>
              <input
                id="plc-port"
                v-model="plcConfig.port"
                class="config-input"
                type="number"
                placeholder="502"
                @focus="handleConfigFocus"
                @blur="handleConfigBlur"
              />
            </div>
            <div class="config-item">
              <label class="config-label">
                <i class="fas fa-map-marker-alt"></i>
                写入地址
              </label>
              <input
                id="plc-writeAddress"
                v-model="plcConfig.writeAddress"
                class="config-input"
                type="text"
                placeholder="例如: DM2370 或 2370"
                @focus="handleConfigFocus"
                @blur="handleConfigBlur"
              />
            </div>
          </div>
          
          <div class="config-actions">
            <button @click="testPlcConnectionHandler" 
                    :class="['test-btn', { 'connected': isPlcConnected }]" 
                    :disabled="isTestingConnection">
              <i :class="isTestingConnection ? 'fas fa-spinner fa-spin' : (isPlcConnected ? 'fas fa-check' : 'fas fa-plug')"></i>
              {{ isTestingConnection ? '测试中...' : (isPlcConnected ? '已连接' : '测试连接') }}
            </button>
            <button @click="savePlcConfig" class="save-config-btn">
              <i class="fas fa-save"></i>
              应用到系统
            </button>
          </div>
        </div>
      </div>

      <div class="scan-input-section">
        <div class="input-wrapper">
          <label for="scanInput" class="input-label">
            <i class="fas fa-barcode"></i>
            扫码输入
          </label>
          <input
            id="scanInput"
            ref="scanInputRef"
            v-model="scanData"
            @input="handleScanInput"
            @keydown.enter="handleEnterKey"
            @focus="handleInputFocus"
            @blur="handleInputBlur"
            class="scan-input"
            type="text"
            :placeholder="isConfigComplete ? '请使用扫码枪扫描条码...' : '请先完成PLC配置后再扫码'"
            autocomplete="off"
            :disabled="isProcessing || !isConfigComplete"
          />
          <div class="input-border"></div>
        </div>

        <!-- 扫码历史记录 -->
        <div class="scan-history" v-if="scanHistory.length > 0">
          <h3 class="history-title">
            <i class="fas fa-history"></i>
            扫码记录 ({{ scanHistory.length }})
          </h3>
          <div class="history-list">
            <div
              v-for="(record, index) in scanHistory"
              :key="index"
              class="history-item"
              :class="{ 'latest': index === 0 }"
            >
              <div class="record-info">
                <div class="record-data">
                  <i class="fas fa-barcode"></i>
                  {{ record.data }}
                </div>
                <div class="record-address" v-if="record.writeAddress">
                  <i class="fas fa-map-marker-alt"></i>
                  地址: {{ record.writeAddress }}
                </div>
              </div>
              <div class="record-time">
                {{ record.time }}
              </div>
              <button @click="removeRecord(index)" class="remove-btn">
                <i class="fas fa-times"></i>
              </button>
            </div>
          </div>
          
          <div class="history-actions">
            <button @click="clearHistory" class="clear-btn">
              <i class="fas fa-trash-alt"></i>
              清空记录
            </button>
            <button @click="exportHistory" class="export-btn">
              <i class="fas fa-download"></i>
              导出数据
            </button>
          </div>
        </div>
      </div>

      <!-- 操作提示 -->
      <div class="scan-tips">
        <div class="tip-item">
          <i class="fas fa-info-circle"></i>
          <span>将光标置于输入框内，使用扫码枪扫描条码</span>
        </div>
        <div class="tip-item">
          <i class="fas fa-keyboard"></i>
          <span>也可手动输入后按回车键确认</span>
        </div>
      </div>
    </div>

    <!-- 通知提示 -->
    <div
      class="notification"
      :class="{ 
        'show': notification.visible, 
        'success': notification.type === 'success', 
        'error': notification.type === 'error',
        'warning': notification.type === 'warning'
      }"
      v-show="notification.visible"
    >
      <div class="notification-content">
        <i :class="getNotificationIcon()" class="notification-icon"></i>
        <span class="notification-message">{{ notification.message }}</span>
      </div>
    </div>
  </main>
</template>

<script setup>
import { ref, reactive, onMounted, onUnmounted, nextTick, watch, computed } from 'vue';
import { writeToPLC, writeStringToPLC, testPlcConnection, getConnectionStatus, isPlcClientOpen, updateListenAddresses, updateBaseAddressMap } from '@/services/plc_service'; // 导入PLC服务
import { getConfig, setConfig } from '@/mapper/config-store'; // 导入配置存储

// 响应式数据
const scanData = ref('');
const scanInputRef = ref(null);
const isProcessing = ref(false);
const isFocused = ref(false);
const scanStatus = ref('waiting'); // waiting, scanning, success, error
const showConfigPanel = ref(false);
const isTestingConnection = ref(false);
const isPlcConnected = ref(false); // PLC连接状态
const configSaved = ref(false); // 配置保存状态指示
const isEditingConfig = ref(false); // 是否正在编辑配置
let editingTimer = null; // 编辑状态定时器

// 计算配置完整性
const isConfigComplete = computed(() => {
  try {
    return !!(plcConfig.ipAddress && plcConfig.port && plcConfig.writeAddress);
  } catch (error) {
    console.error('计算配置完整性时出错:', error);
    return false;
  }
});

// 获取未配置的项目（computed）
const missingConfigItems = computed(() => {
  try {
    const missing = [];
    if (!plcConfig.ipAddress) missing.push('IP地址');
    if (!plcConfig.port) missing.push('端口');
    if (!plcConfig.writeAddress) missing.push('写入地址');
    return missing;
  } catch (error) {
    console.error('获取缺失配置项时出错:', error);
    return ['配置信息'];
  }
});

// 获取未配置项目的文本
const missingConfigText = computed(() => {
  return missingConfigItems.value.join('、');
});

// 验证写入地址是否有效（支持DM前缀）
const validateWriteAddress = (address) => {
  if (!address) return false;
  
  // 处理PLC地址前缀
  let numericAddress = address;
  if (typeof address === 'string') {
    numericAddress = address.replace(/[A-Za-z]/g, '');
  }
  
  const addr = parseInt(numericAddress);
  return !isNaN(addr) && addr > 0 && addr <= 65535;
};

// 处理配置编辑状态
const handleConfigFocus = () => {
  isEditingConfig.value = true;
  if (editingTimer) {
    clearTimeout(editingTimer);
  }
};

const handleConfigBlur = () => {
  // 延迟重置编辑状态，防止在输入框之间切换时误判
  editingTimer = setTimeout(() => {
    isEditingConfig.value = false;
  }, 1000);
};

// PLC配置 - 不设置默认写入地址，完全由用户配置
const plcConfig = reactive({
  ipAddress: '',
  port: null,
  writeAddress: null
});

// 防抖保存定时器
let saveConfigTimer = null;

// 保存配置到本地缓存（防抖处理）
const saveConfigToLocal = () => {
  // 清除之前的定时器
  if (saveConfigTimer) {
    clearTimeout(saveConfigTimer);
  }
  
  // 设置新的定时器，500ms后执行保存
  saveConfigTimer = setTimeout(() => {
    try {
      const configToSave = {
        ipAddress: plcConfig.ipAddress,
        port: plcConfig.port,
        writeAddress: plcConfig.writeAddress,
        lastUpdated: new Date().toISOString()
      };
      localStorage.setItem('plcConfig', JSON.stringify(configToSave));
      console.log('PLC配置已自动缓存到本地:', configToSave);
      
      // 显示保存指示
      configSaved.value = true;
      setTimeout(() => {
        configSaved.value = false;
      }, 1500);
    } catch (error) {
      console.error('保存配置到本地失败:', error);
    }
  }, 500);
};

// 监听配置变化，自动保存到本地缓存
watch(() => plcConfig.ipAddress, saveConfigToLocal);
watch(() => plcConfig.port, saveConfigToLocal);
watch(() => plcConfig.writeAddress, saveConfigToLocal);

// 监听配置完整性变化
watch(isConfigComplete, (isComplete, wasComplete) => {
  // 只在从不完整变为完整时提示
  if (isComplete && wasComplete === false) {
    console.log('PLC配置已完成');
    // 显示配置完成提示
    nextTick(() => {
      setTimeout(() => {
        showNotification('PLC配置已完成，现在可以进行扫码', 'success');
      }, 500);
    });
  }
});

// 扫码历史记录
const scanHistory = reactive([]);

// 通知系统
const notification = reactive({
  visible: false,
  message: '',
  type: 'success' // success, error, warning
});

// 辅助函数：将字符串转换为寄存器值
function stringToRegisters(str) {
  const registers = [];
  // 确保字符串长度为偶数，如果为奇数则补空格
  const paddedStr = str.length % 2 === 0 ? str : str + ' ';
  
  for (let i = 0; i < paddedStr.length; i += 2) {
    const char1 = paddedStr[i] ? paddedStr.charCodeAt(i) : 0;
    const char2 = paddedStr[i + 1] ? paddedStr.charCodeAt(i + 1) : 0;
    // 低字节在前，高字节在后（与服务器端保持一致）
    registers.push((char2 << 8) | char1);
  }
  
  return registers;
}

// 测试函数：模拟PLC的字符串读取逻辑
function registersToString(registers) {
  try {
    return registers.map(item => {
      const hexString = item.toString(16).padStart(4, '0');
      const firstChar = String.fromCharCode(parseInt(hexString.substring(2, 4), 16));
      const secondChar = String.fromCharCode(parseInt(hexString.substring(0, 2), 16));
      return firstChar + secondChar;
    }).join('')
      .replace(/\u0000/g, '')         // 去掉空字符
      .replace(/[\r\n\t\f\b]/g, '')   // 去掉换行、回车、制表等控制符
      .trim(); // 去掉首尾空格
  } catch (e) {
    console.log('registersToString 错误:', registers);
    return '';
  }
}

// 测试字符串转换的正确性
function testStringConversion(testStr) {
  console.log(`=== 测试字符串转换: "${testStr}" ===`);
  const registers = stringToRegisters(testStr);
  console.log('转换为寄存器:', registers);
  console.log('寄存器十六进制:', registers.map(r => '0x' + r.toString(16).padStart(4, '0')));
  const readBack = registersToString(registers);
  console.log('读回的字符串:', `"${readBack}"`);
  console.log('转换是否正确:', testStr.trim() === readBack);
  console.log('');
  return testStr.trim() === readBack;
}

// 获取状态图标
const getStatusIcon = () => {
  switch (scanStatus.value) {
    case 'waiting':
      return 'fas fa-clock';
    case 'scanning':
      return 'fas fa-spinner fa-spin';
    case 'success':
      return 'fas fa-check-circle';
    case 'error':
      return 'fas fa-exclamation-circle';
    default:
      return 'fas fa-clock';
  }
};

// 获取状态文本
const getStatusText = () => {
  try {
    // 如果配置不完整，显示配置提示
    if (!isConfigComplete.value && scanStatus.value === 'waiting') {
      return '请先配置PLC';
    }
    
    switch (scanStatus.value) {
      case 'waiting':
        return '等待扫码';
      case 'scanning':
        return '处理中...';
      case 'success':
        return '扫码成功';
      case 'error':
        return '扫码失败';
      default:
        return '等待扫码';
    }
  } catch (error) {
    console.error('获取状态文本时出错:', error);
    return '状态未知';
  }
};

// 获取通知图标
const getNotificationIcon = () => {
  switch (notification.type) {
    case 'success':
      return 'fas fa-check-circle';
    case 'error':
      return 'fas fa-exclamation-circle';
    case 'warning':
      return 'fas fa-exclamation-triangle';
    default:
      return 'fas fa-info-circle';
  }
};

// 显示通知
const showNotification = (message, type = 'success', duration = 3000) => {
  notification.message = message;
  notification.type = type;
  notification.visible = true;
  
  setTimeout(() => {
    notification.visible = false;
  }, duration);
};

// 处理扫码输入
const handleScanInput = () => {
  if (scanData.value.length > 0) {
    scanStatus.value = 'scanning';
  } else {
    scanStatus.value = 'waiting';
  }
};

// 处理回车键
const handleEnterKey = () => {
  if (scanData.value.trim()) {
    processScanData(scanData.value.trim());
  }
};

// 处理输入框聚焦
const handleInputFocus = () => {
  isFocused.value = true;
  scanStatus.value = 'waiting';
};

// 处理输入框失焦
const handleInputBlur = () => {
  isFocused.value = false;
};

// 切换配置面板
const toggleConfigPanel = () => {
  showConfigPanel.value = !showConfigPanel.value;
};

// 立即保存配置（不使用防抖）
const saveConfigImmediately = () => {
  try {
    const configToSave = {
      ipAddress: plcConfig.ipAddress,
      port: plcConfig.port,
      writeAddress: plcConfig.writeAddress,
      lastUpdated: new Date().toISOString()
    };
    localStorage.setItem('plcConfig', JSON.stringify(configToSave));
    console.log('PLC配置已立即保存到本地:', configToSave);
  } catch (error) {
    console.error('保存配置到本地失败:', error);
  }
};

// 保存PLC配置到系统配置中
const savePlcConfig = async () => {
  try {
    // 立即保存到本地缓存
    saveConfigImmediately();
    
    // 保存到系统配置中，包含所有用户配置的项目
    await setConfig('plcConfig', {
      ip: plcConfig.ipAddress,
      port: plcConfig.port,
      writeAddress: plcConfig.writeAddress
    });
    
    showNotification('PLC配置已保存到系统配置', 'success');
  } catch (error) {
    console.error('保存PLC配置失败:', error);
    showNotification('保存系统配置失败', 'error');
  }
};

// 加载PLC配置 - 完全从缓存加载，不设置默认值
const loadPlcConfig = async () => {
  try {
    let configLoaded = false;
    
    // 优先从localStorage加载（用户配置的本地缓存）
    const saved = localStorage.getItem('plcConfig');
    if (saved) {
      const config = JSON.parse(saved);
      console.log('从本地缓存加载PLC配置:', config);
      
      // 只设置存在的配置项，不设置默认值
      if (config.ipAddress) plcConfig.ipAddress = config.ipAddress;
      if (config.port) plcConfig.port = config.port;
      if (config.writeAddress) plcConfig.writeAddress = config.writeAddress;
      
      configLoaded = true;
    }
    
    // 如果本地没有配置，尝试从系统配置加载
    if (!configLoaded) {
      const systemConfig = await getConfig('plcConfig');
      if (systemConfig) {
        console.log('从系统配置加载PLC配置:', systemConfig);
        if (systemConfig.ip) plcConfig.ipAddress = systemConfig.ip;
        if (systemConfig.port) plcConfig.port = systemConfig.port;
        if (systemConfig.writeAddress) plcConfig.writeAddress = systemConfig.writeAddress;
      }
    }
    
    console.log('最终加载的PLC配置:', {
      ipAddress: plcConfig.ipAddress,
      port: plcConfig.port,
      writeAddress: plcConfig.writeAddress
    });
  } catch (error) {
    console.error('加载PLC配置失败:', error);
  }
};

// 测试PLC连接 - 直接使用PLC服务
const testPlcConnectionHandler = async () => {
  if (!plcConfig.ipAddress || !plcConfig.port || !plcConfig.writeAddress) {
    showNotification('请填写完整的PLC配置', 'warning');
    return;
  }
  
  isTestingConnection.value = true;
  
  try {
    // 保存配置到系统配置中，以便PLC服务使用
    await setConfig('plcConfig', {
      ip: plcConfig.ipAddress,
      port: plcConfig.port,
      writeAddress: plcConfig.writeAddress
    });
    
    console.log(`尝试连接PLC: ${plcConfig.ipAddress}:${plcConfig.port}`);
    
    // 使用PLC服务的测试连接函数
    const connected = await testPlcConnection();
    
    if (connected) {
      isPlcConnected.value = true;
      
      // 配置PLC监听地址，确保能读取用户配置的地址
      console.log(`配置PLC监听地址: ${plcConfig.writeAddress}`);
      updateListenAddresses(plcConfig.writeAddress, 30);
      updateBaseAddressMap(plcConfig.writeAddress, 30);
      
      showNotification('PLC连接测试成功', 'success');
      console.log('PLC连接状态:', getConnectionStatus());
      
      // 测试字符串转换和地址处理
      console.log('=== 开始测试字符串转换 ===');
      testStringConversion('1310200101001 2504037536');
      testStringConversion('13');
      testStringConversion('1234');
      testStringConversion('AB CD');
      console.log('=== 字符串转换测试结束 ===');
      
      // 测试地址验证
      console.log('=== 测试地址验证 ===');
      console.log('2370 验证结果:', validateWriteAddress('2370'));
      console.log('DM2370 验证结果:', validateWriteAddress('DM2370'));
      console.log('MW8100 验证结果:', validateWriteAddress('MW8100'));
      console.log('空地址 验证结果:', validateWriteAddress(''));
      console.log('=== 地址验证测试结束 ===');
    } else {
      isPlcConnected.value = false;
      showNotification('PLC连接失败', 'error');
    }
  } catch (error) {
    console.error('测试连接失败:', error);
    isPlcConnected.value = false;
    showNotification(`连接测试失败: ${error.message}`, 'error');
  } finally {
    isTestingConnection.value = false;
  }
};

// 写入数据到PLC - 使用与modbus.js相同的方式
const writeBarcodeToPLC = async (barcodeData) => {
  try {
    // 检查PLC连接状态
    if (!isPlcConnected.value || !isPlcClientOpen()) {
      throw new Error('PLC未连接，请先测试连接');
    }
    
    console.log(`=== 使用modbus.js相同方式写入条码 ===`);
    console.log(`原始条码: "${barcodeData}"`);
    console.log(`写入地址: ${plcConfig.writeAddress}`);
    console.log(`IP地址: ${plcConfig.ipAddress}:${plcConfig.port}`);
    
    // 使用新的writeStringToPLC函数，采用与modbus.js相同的方式
    await writeStringToPLC(plcConfig.writeAddress, barcodeData);
    
    console.log(`条码写入成功: ${barcodeData}`);
    showNotification(`条码已写入PLC地址${plcConfig.writeAddress}`, 'success');
    return true;
  } catch (error) {
    console.error('写入PLC失败:', error);
    showNotification(`写入PLC失败: ${error.message}`, 'error');
    return false;
  }
};

// 处理扫码数据
const processScanData = async (data) => {
  if (!data || isProcessing.value) return;
  
  // 检查是否已配置地址
  if (!isConfigComplete.value) {
    const missing = missingConfigItems.value;
    showNotification(`请先配置：${missing.join('、')}`, 'warning');
    
    // 自动展开配置面板
    showConfigPanel.value = true;
    scanStatus.value = 'error';
    
    // 聚焦到第一个未配置的输入框
    await nextTick();
    if (!plcConfig.ipAddress) {
      document.getElementById('plc-ip')?.focus();
    } else if (!plcConfig.port) {
      document.getElementById('plc-port')?.focus();
    } else if (!plcConfig.writeAddress) {
      document.getElementById('plc-writeAddress')?.focus();
    }
    
    setTimeout(() => {
      scanStatus.value = 'waiting';
    }, 2000);
    
    return;
  }
  
  // 检查PLC是否已连接
  if (!isPlcConnected.value || !isPlcClientOpen()) {
    showNotification('PLC未连接，请先测试连接', 'warning');
    // 自动展开配置面板
    showConfigPanel.value = true;
    scanStatus.value = 'error';
    
    setTimeout(() => {
      scanStatus.value = 'waiting';
    }, 2000);
    
    return;
  }
  
  isProcessing.value = true;
  scanStatus.value = 'scanning';
  
  try {
    // 检查是否是重复数据
    const isDuplicate = scanHistory.some(record => record.data === data);
    
    if (isDuplicate) {
      showNotification('检测到重复条码！', 'warning');
      scanStatus.value = 'error';
    } else {
      // 写入PLC
      const writeSuccess = await writeBarcodeToPLC(data);
      
      if (writeSuccess) {
        // 添加到历史记录
        const record = {
          data: data,
          time: new Date().toLocaleString(),
          timestamp: Date.now(),
          writeAddress: plcConfig.writeAddress,
          status: 'success'
        };
        
        scanHistory.unshift(record);
        
        // 限制历史记录数量
        if (scanHistory.length > 100) {
          scanHistory.splice(100);
        }
        
        showNotification(`扫码成功并写入PLC地址${plcConfig.writeAddress}: ${data}`, 'success');
        scanStatus.value = 'success';
        
        console.log('扫码数据:', data);
        console.log('写入地址:', plcConfig.writeAddress);
        console.log('历史记录:', scanHistory);
      } else {
        scanStatus.value = 'error';
      }
    }
    
    // 清空输入框
    scanData.value = '';
    
    // 重新聚焦输入框
    await nextTick();
    if (scanInputRef.value) {
      scanInputRef.value.focus();
    }
    
    // 重置状态
    setTimeout(() => {
      scanStatus.value = 'waiting';
    }, 1500);
    
  } catch (error) {
    console.error('处理扫码数据失败:', error);
    showNotification('处理失败，请重试', 'error');
    scanStatus.value = 'error';
    
    setTimeout(() => {
      scanStatus.value = 'waiting';
    }, 2000);
  } finally {
    isProcessing.value = false;
  }
};

// 移除单条记录
const removeRecord = (index) => {
  const removedRecord = scanHistory.splice(index, 1)[0];
  showNotification(`已删除记录: ${removedRecord.data}`, 'success');
};

// 清空历史记录
const clearHistory = () => {
  if (scanHistory.length > 0) {
    scanHistory.splice(0);
    showNotification('已清空所有记录', 'success');
  }
};

// 导出历史数据
const exportHistory = () => {
  if (scanHistory.length === 0) {
    showNotification('暂无数据可导出', 'warning');
    return;
  }
  
  try {
    const dataStr = scanHistory.map(record => 
      `${record.data}\t${record.time}`
    ).join('\n');
    
    const blob = new Blob([`条码\t时间\n${dataStr}`], { type: 'text/plain;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    
    const link = document.createElement('a');
    link.href = url;
    link.download = `扫码记录_${new Date().toISOString().split('T')[0]}.txt`;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    
    URL.revokeObjectURL(url);
    showNotification('数据导出成功', 'success');
  } catch (error) {
    console.error('导出失败:', error);
    showNotification('导出失败，请重试', 'error');
  }
};

// 自动聚焦输入框（智能判断）
const autoFocus = () => {
  // 如果正在处理扫码，不聚焦
  if (isProcessing.value) return;
  
  // 如果正在编辑配置，不聚焦
  if (isEditingConfig.value) return;
  
  // 检查当前焦点元素
  const activeElement = document.activeElement;
  
  // 如果当前焦点在配置输入框上，不要抢夺焦点
  if (activeElement && (
    activeElement.id === 'plc-ip' ||
    activeElement.id === 'plc-port' ||
    activeElement.id === 'plc-writeAddress' ||
    activeElement.type === 'text' ||
    activeElement.type === 'number' ||
    activeElement.classList.contains('config-input')
  )) {
    return;
  }
  
  // 如果配置面板展开，减少聚焦
  if (showConfigPanel.value) {
    return;
  }
  
  // 否则聚焦到扫码输入框
  if (scanInputRef.value) {
    scanInputRef.value.focus();
  }
};

// 生命周期
onMounted(async () => {
  // 加载PLC配置
  await loadPlcConfig();
  
  // 检查配置完整性，首次使用时提示用户
  if (!isConfigComplete.value) {
    console.log('检测到配置不完整，显示配置面板');
    showConfigPanel.value = true;
    setTimeout(() => {
      showNotification('欢迎使用！请先配置PLC连接信息', 'warning', 5000);
    }, 1000);
  }
  
  // 检查初始PLC连接状态
  try {
    isPlcConnected.value = getConnectionStatus() && isPlcClientOpen();
    console.log('初始PLC连接状态:', isPlcConnected.value);
  } catch (error) {
    console.log('检查PLC连接状态失败:', error);
    isPlcConnected.value = false;
  }
  
  // 页面加载时自动聚焦
  nextTick(() => {
    autoFocus();
  });
  
  // 定期自动聚焦（防止焦点丢失）
  const focusInterval = setInterval(autoFocus, 3000); // 延长间隔到3秒
  
  // 监听全局点击事件，智能处理聚焦
  const handleGlobalClick = (event) => {
    // 如果点击的是配置相关的元素，不要自动聚焦到扫码框
    const target = event.target;
    if (target && (
      target.closest('.plc-config-section') ||
      target.classList.contains('config-input') ||
      target.id === 'plc-ip' ||
      target.id === 'plc-port' ||
      target.id === 'plc-writeAddress'
    )) {
      return;
    }
    
    // 延迟聚焦，给其他元素获得焦点的机会
    setTimeout(autoFocus, 100);
  };
  
  document.addEventListener('click', handleGlobalClick);
  
  // 清理函数
  onUnmounted(() => {
    try {
      clearInterval(focusInterval);
      document.removeEventListener('click', handleGlobalClick);
      
      // 清理配置保存定时器
      if (saveConfigTimer) {
        clearTimeout(saveConfigTimer);
        saveConfigTimer = null;
      }
      
      // 清理编辑状态定时器
      if (editingTimer) {
        clearTimeout(editingTimer);
        editingTimer = null;
      }
    } catch (error) {
      console.error('清理资源时出错:', error);
    }
  });
});
</script>

<style>
/* 全局样式 - 禁止页面垂直滚动 */
html, body {
  height: 100%;
  max-height: 100%;
  overflow-x: auto;
  overflow-y: hidden;
}

#app {
  height: 100vh;
  max-height: 100vh;
  overflow: hidden;
}
</style>

<style scoped>
/* 全局容器 - 响应式居中布局 */
.scan-container {
  height: 100vh;
  max-height: 100vh;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  font-family: 'Microsoft YaHei', sans-serif;
  overflow-x: auto;
  overflow-y: hidden;
}

/* 主卡片 - 响应式适应 */
.scan-card {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  border-radius: 2rem;
  box-shadow: 
    0 25px 50px -12px rgba(0, 0, 0, 0.25),
    0 0 0 1px rgba(255, 255, 255, 0.2);
  padding: 2rem;
  width: 100%;
  max-width: 800px;
  max-height: calc(100vh - 2rem);
  position: relative;
  overflow-y: auto;
  overflow-x: hidden;
  flex-shrink: 0;
}

.scan-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, #667eea, #764ba2, #f093fb, #f5576c);
  border-radius: 2rem 2rem 0 0;
}

/* 头部区域 */
.scan-header {
  text-align: center;
  margin-bottom: 3rem;
}

.scan-title {
  font-size: 2.5rem;
  font-weight: 700;
  color: #2d3748;
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}

.scan-title i {
  color: #667eea;
  font-size: 2.8rem;
}

.scan-status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  border-radius: 2rem;
  font-weight: 600;
  font-size: 1.1rem;
  transition: all 0.3s ease;
}

.scan-status.waiting {
  background: linear-gradient(135deg, #e2e8f0, #cbd5e0);
  color: #4a5568;
}

.scan-status.scanning {
  background: linear-gradient(135deg, #bee3f8, #90cdf4);
  color: #2b6cb0;
}

.scan-status.success {
  background: linear-gradient(135deg, #c6f6d5, #9ae6b4);
  color: #276749;
}

.scan-status.error {
  background: linear-gradient(135deg, #fed7d7, #feb2b2);
  color: #c53030;
}

/* PLC配置区域 */
.plc-config-section {
  background: linear-gradient(135deg, #f0f9ff, #e0f2fe);
  border-radius: 1.5rem;
  padding: 1.5rem;
  margin-bottom: 2rem;
  border: 1px solid #bae6fd;
  box-shadow: 0 10px 25px -5px rgba(14, 165, 233, 0.1);
}

.config-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.config-title {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 1.3rem;
  font-weight: 700;
  color: #0369a1;
  margin: 0;
}

.config-title i {
  color: #0ea5e9;
}

.config-saved-indicator {
  margin-left: 0.75rem;
  font-size: 0.8rem;
  color: #059669;
  background: linear-gradient(135deg, #d1fae5, #a7f3d0);
  padding: 0.25rem 0.75rem;
  border-radius: 1rem;
  border: 1px solid #6ee7b7;
  animation: fadeInOut 1.5s ease-in-out;
}

.config-saved-indicator i {
  color: #047857;
  margin-right: 0.25rem;
}

.config-incomplete-indicator {
  margin-left: 0.75rem;
  font-size: 0.8rem;
  color: #dc2626;
  background: linear-gradient(135deg, #fee2e2, #fecaca);
  padding: 0.25rem 0.75rem;
  border-radius: 1rem;
  border: 1px solid #f87171;
  animation: pulse 2s ease-in-out infinite;
}

.config-incomplete-indicator i {
  color: #b91c1c;
  margin-right: 0.25rem;
}

.config-status-alert {
  background: linear-gradient(135deg, #fffbeb, #fef3c7);
  border: 1px solid #f59e0b;
  border-radius: 0.75rem;
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
  color: #92400e;
  font-size: 0.9rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.config-status-alert i {
  color: #f59e0b;
  font-size: 1rem;
}

@keyframes fadeInOut {
  0% { opacity: 0; transform: scale(0.8); }
  20% { opacity: 1; transform: scale(1); }
  80% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.8); }
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.7; }
}

.toggle-config-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: linear-gradient(135deg, #0ea5e9, #0284c7);
  color: white;
  border: none;
  border-radius: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.toggle-config-btn:hover {
  background: linear-gradient(135deg, #0284c7, #0369a1);
  transform: translateY(-1px);
}

.config-panel {
  margin-top: 1rem;
}

.config-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
}

/* 配置网格响应式 */
@media (max-width: 768px) {
  .config-grid {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 0.75rem;
  }
}

@media (max-width: 480px) {
  .config-grid {
    grid-template-columns: 1fr;
    gap: 0.75rem;
  }
}

.config-item {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.config-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: #0369a1;
}

.config-label i {
  color: #0ea5e9;
}

.config-input {
  padding: 0.75rem 1rem;
  border: 2px solid #bae6fd;
  border-radius: 0.75rem;
  font-size: 0.9rem;
  background: white;
  color: #1e293b;
  transition: all 0.2s ease;
}

.config-input:focus {
  outline: none;
  border-color: #0ea5e9;
  box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
}

.config-actions {
  display: flex;
  gap: 1rem;
  justify-content: center;
}

.test-btn,
.save-config-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  border: none;
  border-radius: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.test-btn {
  background: linear-gradient(135deg, #f59e0b, #d97706);
  color: white;
}

.test-btn:hover:not(:disabled) {
  background: linear-gradient(135deg, #d97706, #b45309);
  transform: translateY(-1px);
}

.test-btn:disabled {
  opacity: 0.7;
  cursor: not-allowed;
}

/* 连接成功状态的按钮样式 */
.test-btn.connected {
  background: linear-gradient(135deg, #10b981, #059669);
}

.save-config-btn {
  background: linear-gradient(135deg, #10b981, #059669);
  color: white;
}

.save-config-btn:hover {
  background: linear-gradient(135deg, #059669, #047857);
  transform: translateY(-1px);
}

/* 输入区域 */
.scan-input-section {
  margin-bottom: 2rem;
}

.input-wrapper {
  position: relative;
  margin-bottom: 2rem;
}

.input-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1.2rem;
  font-weight: 600;
  color: #4a5568;
  margin-bottom: 1rem;
}

.input-label i {
  color: #667eea;
}

.scan-input {
  width: 100%;
  padding: 1.5rem 2rem;
  font-size: 1.2rem;
  border: 3px solid transparent;
  border-radius: 1.5rem;
  background: linear-gradient(135deg, #f7fafc, #edf2f7);
  color: #2d3748;
  font-weight: 500;
  transition: all 0.3s ease;
  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
  position: relative;
  z-index: 1;
}

.scan-input:focus {
  outline: none;
  border-color: #667eea;
  background: white;
  box-shadow: 
    0 0 0 3px rgba(102, 126, 234, 0.1),
    0 15px 35px -5px rgba(102, 126, 234, 0.2);
  transform: translateY(-2px);
}

.scan-input:disabled {
  opacity: 0.7;
  cursor: not-allowed;
  background: linear-gradient(135deg, #f9fafb, #f3f4f6);
  color: #6b7280;
  border-color: #d1d5db;
}

.input-border {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 0;
  height: 3px;
  background: linear-gradient(90deg, #667eea, #764ba2);
  border-radius: 1.5px;
  transition: all 0.3s ease;
  transform: translateX(-50%);
}

.scan-input:focus + .input-border {
  width: 100%;
}

/* 历史记录 */
.scan-history {
  background: linear-gradient(135deg, #f8fafc, #e2e8f0);
  border-radius: 1.5rem;
  padding: 2rem;
  margin-top: 2rem;
  border: 1px solid #e2e8f0;
}

.history-title {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 1.3rem;
  font-weight: 700;
  color: #2d3748;
  margin-bottom: 1.5rem;
}

.history-title i {
  color: #667eea;
}

.history-list {
  max-height: 200px;
  overflow-y: auto;
  margin-bottom: 1.5rem;
}

.history-list::-webkit-scrollbar {
  width: 6px;
}

.history-list::-webkit-scrollbar-track {
  background: #f1f5f9;
  border-radius: 3px;
}

.history-list::-webkit-scrollbar-thumb {
  background: #667eea;
  border-radius: 3px;
}

.history-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem;
  margin-bottom: 0.75rem;
  background: white;
  border-radius: 1rem;
  border: 1px solid #e2e8f0;
  transition: all 0.2s ease;
}

.record-info {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex: 1;
}

.history-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
  border-color: #cbd5e0;
}

.history-item.latest {
  background: linear-gradient(135deg, #e6fffa, #b2f5ea);
  border-color: #81e6d9;
}

.record-data {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: 'Consolas', monospace;
  font-weight: 600;
  color: #2d3748;
  flex: 1;
}

.record-data i {
  color: #667eea;
}

.record-address {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: #059669;
  background: linear-gradient(135deg, #d1fae5, #a7f3d0);
  padding: 0.25rem 0.75rem;
  border-radius: 1rem;
  border: 1px solid #6ee7b7;
  width: fit-content;
}

.record-address i {
  color: #047857;
}

.record-time {
  font-size: 0.9rem;
  color: #718096;
  font-weight: 500;
  margin-right: 1rem;
}

.remove-btn {
  background: #fed7d7;
  color: #c53030;
  border: none;
  border-radius: 50%;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s ease;
}

.remove-btn:hover {
  background: #feb2b2;
  transform: scale(1.1);
}

.history-actions {
  display: flex;
  gap: 1rem;
  justify-content: center;
}

.clear-btn,
.export-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  border: none;
  border-radius: 1rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.clear-btn {
  background: linear-gradient(135deg, #fed7d7, #feb2b2);
  color: #c53030;
}

.clear-btn:hover {
  background: linear-gradient(135deg, #feb2b2, #fc8181);
  transform: translateY(-2px);
}

.export-btn {
  background: linear-gradient(135deg, #c6f6d5, #9ae6b4);
  color: #276749;
}

.export-btn:hover {
  background: linear-gradient(135deg, #9ae6b4, #68d391);
  transform: translateY(-2px);
}

/* 操作提示 */
.scan-tips {
  background: linear-gradient(135deg, #fffbeb, #fef3c7);
  border-radius: 1rem;
  padding: 1.5rem;
  border: 1px solid #f59e0b;
}

.tip-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
  color: #92400e;
  font-weight: 500;
}

.tip-item:last-child {
  margin-bottom: 0;
}

.tip-item i {
  color: #f59e0b;
  font-size: 1.1rem;
}

/* 通知提示 */
.notification {
  position: fixed;
  top: 2rem;
  right: 2rem;
  padding: 1rem 1.5rem;
  border-radius: 1rem;
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
  z-index: 1000;
  opacity: 0;
  transform: translateX(100%);
  transition: all 0.3s ease;
  min-width: 300px;
  max-width: calc(100vw - 4rem);
}

.notification.show {
  opacity: 1;
  transform: translateX(0);
}

.notification.success {
  background: linear-gradient(135deg, #c6f6d5, #9ae6b4);
  color: #276749;
  border: 1px solid #68d391;
}

.notification.error {
  background: linear-gradient(135deg, #fed7d7, #feb2b2);
  color: #c53030;
  border: 1px solid #fc8181;
}

.notification.warning {
  background: linear-gradient(135deg, #fef3c7, #fde68a);
  color: #92400e;
  border: 1px solid #f59e0b;
}

.notification-content {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.notification-icon {
  font-size: 1.25rem;
  flex-shrink: 0;
}

.notification-message {
  font-weight: 600;
  font-size: 1rem;
}

/* 中等屏幕适配 */
@media (max-width: 1024px) {
  .scan-card {
    max-width: 700px;
    padding: 1.8rem;
  }
}

/* 平板适配 */
@media (max-width: 768px) {
  .scan-container {
    padding: 0.75rem;
  }
  
  .scan-card {
    padding: 1.5rem;
    max-width: none;
    width: 100%;
    max-height: calc(100vh - 1.5rem);
  }
  
  .scan-title {
    font-size: 1.8rem;
    flex-direction: column;
    gap: 0.5rem;
  }
  
  .scan-title i {
    font-size: 2rem;
  }
  
  .scan-input {
    padding: 1.25rem 1.5rem;
    font-size: 1.1rem;
  }
  
  .history-list {
    max-height: 150px;
  }
  
  .history-actions {
    flex-direction: column;
  }
  
  .clear-btn,
  .export-btn {
    width: 100%;
    justify-content: center;
  }
  
  .notification {
    top: 1rem;
    right: 1rem;
    left: 1rem;
    min-width: auto;
  }
}

/* 手机适配 */
@media (max-width: 480px) {
  .scan-container {
    padding: 0.5rem;
  }
  
  .scan-card {
    padding: 1rem;
    max-height: calc(100vh - 1rem);
    border-radius: 1.5rem;
  }
  
  .scan-title {
    font-size: 1.5rem;
  }
  
  .scan-input {
    padding: 1rem;
    font-size: 1rem;
  }
  
  .config-grid {
    grid-template-columns: 1fr;
  }
  
  .config-actions {
    flex-direction: column;
    gap: 0.75rem;
  }
  
  .test-btn,
  .save-config-btn {
    width: 100%;
    justify-content: center;
  }
  
  .history-list {
    max-height: 120px;
  }
  
  .history-item {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
  }
  
  .record-time {
    margin-right: 0;
  }
  
  .remove-btn {
    align-self: flex-end;
  }
}

/* 超小屏幕适配 */
@media (max-width: 360px) {
  .scan-container {
    padding: 0.25rem;
  }
  
  .scan-card {
    padding: 0.75rem;
    max-height: calc(100vh - 0.5rem);
    border-radius: 1rem;
  }
  
  .scan-title {
    font-size: 1.3rem;
  }
  
  .scan-title i {
    font-size: 1.5rem;
  }
  
  .scan-input {
    padding: 0.875rem;
    font-size: 0.9rem;
  }
  
  .config-input {
    padding: 0.625rem 0.875rem;
    font-size: 0.85rem;
  }
}
</style>
